package cn.j0.mybatistool;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.mybatis.generator.internal.ObjectFactory;

/**
 * 程序入口 main方法
 *
 */
public class Generator {

	private static String configProperties;
	private static String configTpl;
	private static String config;
	private static Properties prop;
	private static Connection connection;
	
	private static Set<String> autoIncrementTableSet;

	static {
		prop = new Properties();
		configProperties = "src/config.properties";
		configTpl = "src/config.tpl.xml";
		config = "src/generatorConfig.xml";
		
		autoIncrementTableSet = new HashSet<String>();
		autoIncrementTableSet.add("email");
		autoIncrementTableSet.add("software_revision");
		autoIncrementTableSet.add("software_upgrade_log");
		autoIncrementTableSet.add("software_serial_number");
		autoIncrementTableSet.add("sys_user_last_online");
		autoIncrementTableSet.add("sys_user_status_history");
		autoIncrementTableSet.add("sys_user_login_history");
		autoIncrementTableSet.add("sys_user_status_history");
		autoIncrementTableSet.add("partner_history");
		autoIncrementTableSet.add("pdf_chapter");
		autoIncrementTableSet.add("pdf_anchor");
//		autoIncrementTableSet.add("exampaper");
		autoIncrementTableSet.add("proc_resource");
		autoIncrementTableSet.add("client_user_mapping");
		autoIncrementTableSet.add("app_crash_log");
		autoIncrementTableSet.add("user_account_item");
		autoIncrementTableSet.add("pay_gateway_log");

		try {
			File file = new File(configProperties);
			if (!file.exists()) {
				file.createNewFile();
			}
			InputStream in = new FileInputStream(new File(configProperties));
			prop.load(in);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
		File javaFile = new File(prop.getProperty("target.project"));
		File xmlFile = new File(prop.getProperty("target.xml"));
		clearTargetDirectory(javaFile);
		clearTargetDirectory(xmlFile);
		
		while (javaFile.listFiles().length > 0) {
			System.out.print("...");
		}
		
		initConnection();
		String[] input = initWelcome();
		String xmlStr = initTable(input);
		buildConfigXml(xmlStr);

		List<String> warnings = new ArrayList<String>();
		File file = new File(config);

		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration configuration = cp.parseConfiguration(file);

		DefaultShellCallback callback = new DefaultShellCallback(true);
		MyBatisGenerator mybatisGenerator = new MyBatisGenerator(configuration, callback, warnings);
		
		System.out.println("开始生成文件...");
		mybatisGenerator.generate(null);
		System.out.println("完成.");
	}

	public static void initConnection() {
		Properties p = new Properties();
		String driverClass = prop.getProperty("jdbc.driverClass");
		Driver driver = null;

		try {
			Class<?> clazz = ObjectFactory.externalClassForName(driverClass);
			driver = (Driver) clazz.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}

		p.setProperty("user", prop.getProperty("jdbc.user"));
		p.setProperty("password", prop.getProperty("jdbc.password"));
		try {
			connection = driver.connect(prop.getProperty("jdbc.connectionURL"), p);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public static String[] initWelcome() throws Exception {
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		System.out.print("请输入表名, 逗号分割(空则生成所有表):");
		String input = reader.readLine();
		String[] tables = null;

		if ("".equals(input)) {
			System.out.println("生成所有表...");
		} else {
			tables = input.replaceAll(" ", "").split(",");
			System.out.println("生成表: " + Arrays.toString(tables));
		}

		return tables;
	}

	public static String initTable(String[] tables) throws Exception {
		String str = "";
		String tpl = "<table tableName=\"{tableName}\">"
						+ "<generatedKey column=\"{id}\" sqlStatement=\"MySql\" identity=\"true\"></generatedKey>"
					+ "</table>";
		
		String tplNoIncrement = "<table tableName=\"{tableName}\">"
			+ "</table>";
		
		DatabaseMetaData dbMeta = connection.getMetaData();
		ResultSet rs;

		if (tables != null) {
			for (String s : tables) {
				rs = dbMeta.getTables(null, null, s, new String[] { "TABLE" });
				if (rs.next()) {
					ResultSet pkRSet = dbMeta.getPrimaryKeys(null, null, s);
					while( pkRSet.next() ) {
						if(autoIncrementTableSet.contains(s)) {
							str += tpl.replace("{tableName}", s).replace("{id}", String.valueOf(pkRSet.getObject(4)));
						} else {
							str += tplNoIncrement.replace("{tableName}", s);
						}
					}
				} else {
					System.out.println("表: " + s + " 不存在, 程序退出!");
					System.exit(1);
				}
			}
		} else {
			rs = dbMeta.getTables(null, null, null, new String[] { "TABLE" });
			while (rs.next()) {
				ResultSet pkRSet = dbMeta.getPrimaryKeys(null, null, rs.getString(3)); 
				while( pkRSet.next() ) { 
					ResultSetMetaData rsmd = pkRSet.getMetaData();
					if(rsmd.isAutoIncrement(4)) {
						str += tpl.replace("{tableName}", rs.getString(3)).replace("{id}", String.valueOf(pkRSet.getObject(4)));
					} else {
						str += tplNoIncrement.replace("{tableName}", rs.getString(3));
					}
				}
			}
		}

		connection.close();
		return str;
	}

	public static void buildConfigXml(String xmlStr) throws Exception {
		System.out.println("生成: " + config);
		InputStreamReader read = new InputStreamReader(new FileInputStream(new File(configTpl)), "UTF8");
		BufferedReader bufferedReader = new BufferedReader(read);
		StringBuffer sb = new StringBuffer();
		String lineTxt = null;
		while ((lineTxt = bufferedReader.readLine()) != null) {
			sb.append(lineTxt);
		}
		read.close();
		String tpl = sb.toString();

		File file = new File(config);
		if (!file.exists()) {
			file.createNewFile();
		}

		FileWriter fileWritter = new FileWriter(file, false);
		BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
		bufferWritter.write(tpl.replace("<!-- {tables} -->", xmlStr));
		bufferWritter.close();
	}

	public static void clearTargetDirectory(File file) {
		System.out.println("清空目录: " + file.getPath());
		String[] tempList = file.list();
		File temp = null;
		
		for (int i = 0; i < tempList.length; i++) {
			temp = new File(file.getPath() + File.separator + tempList[i]);
			if (temp.isFile()) {
				temp.delete();
			}else {
				deleteDirectory(temp);
			}
		}
	}

	public static void deleteDirectory(File file) {
		try {
			if (file.exists() && file.isDirectory()) {
				String[] contents = file.list();
				for (int i = 0; i < contents.length; i++) {
					File file2X = new File(file.getAbsolutePath() + "/" + contents[i]);
					if (file2X.exists()) {
						if (file2X.isFile()) {
							file2X.delete();
						} else if (file2X.isDirectory()) {
							deleteDirectory(file2X);
						}
					} else {
						throw new RuntimeException("File not exist!");
					}
				}
				file.delete();
			} else {
				throw new RuntimeException("Not a directory!");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
}
